const Installer = require("./installer");
const Path = require("path");
const { File, SyncFile } = require("ada-util");
const { md5 } = require("ada-util/src/md5");

class Maker {
    constructor(config) {
        this._config = config;
        this._installer = new Installer(config);
        let mapPath = Path.resolve(config.cachePath, './.ada.cache.map'), cache = {};
        if (new File(mapPath).exist) {
            cache = JSON.parse(new SyncFile(mapPath).read());
        }
        this._cacheMap = cache;
    }

    get config() {
        return this._config;
    }

    get installer() {
        return this._installer;
    }

    make(path, info) {
        let type = Path.extname(path).substring(1);
        let _file = new File(path);
        return _file.hash().then(hash => {
            let { cachePath } = this._config;
            let target = Path.resolve(cachePath, `./${hash}`);
            this._cacheMap[md5(path)] = hash;
            if (new File(target).exist) {
                return new File(target).read();
            } else {
                return _file.read().then(content => {
                    if (this.config.dependence[type]) {
                        return this.installer.readyTypeModules(type).then(() => {
                            let makers = this.config.make[type] || [];
                            let makerMap = this.config.maker;
                            return makers.reduce((a, maker) => {
                                maker = makerMap[maker];
                                return a.then((code) => {
                                    if (typeof maker === 'string') {
                                        maker = require(maker);
                                    }
                                    return Promise.resolve().then(() => {
                                        return maker({ content: code, path, option: this.config, fileInfo: info });
                                    });
                                });
                            }, Promise.resolve(content)).then(content => {
                                return new File(target).write(content).then(() => {
                                    return content;
                                });
                            });
                        });
                    } else {
                        return Promise.resolve(content);
                    }
                });
            }
        });
    }

    babelCode(code, path) {
        return this.installer.readyTypeModules("js").then(() => {
            let ops = Object.assign({}, this.config.adaCore, { filename: path });
            let content = require(Path.resolve(this.config.nmodulePath, './@babel/core')).transform(code, ops).code;
            try {
                content = require(Path.resolve(this.config.nmodulePath, './uglify-es')).minify(content, Object.assign({}, this.config.compiler.uglify)).code;
            } catch (e) {
            }
            return content;
        });
    }

    minifyCode(code) {
        return this.installer.readyTypeModules("js").then(() => {
            let content = code;
            try {
                content = require(Path.resolve(this.config.nmodulePath, './uglify-es')).minify(content, Object.assign({}, this.config.compiler.uglify)).code;
            } catch (e) {
            }
            return content;
        });
    }

    minifyIcon(content) {
        return this.installer.readyTypeModules("less").then(() => {
            content = require(Path.resolve(this.config.nmodulePath, './html-minifier')).minify(content, {
                removeComments: true,
                collapseWhitespace: true,
                minifyJS: true,
                minifyCSS: true
            });
            let titleTag = content.match(/<title>[\s\S]*?>/);
            let name = "";
            if (titleTag) {
                name = titleTag[0].substring(7, titleTag[0].length - 8).trim();
            }
            let et = content.replace(/svg/g, "symbol").replace(/xmlns\=".*?"/, "").replace(/version\=".*?"/, "").replace(/viewBox\=".*?"/, (str) => {
                return `${str} id="${name}"`;
            });
            let code = `<svg style="width:0;height:0;overflow:hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">${et}</svg>`;
            return { name, code };
        });
    }

    lessCode(content) {
        return this.installer.readyTypeModules("less").then(() => {
            return new Promise((resolve, reject) => {
                require(Path.resolve(this.config.nmodulePath, './less')).render(content, (e, output) => {
                    if (!e) {
                        let code = require(Path.resolve(this.config.nmodulePath, './html-minifier')).minify(output.css, {
                            removeComments: true,
                            collapseWhitespace: true,
                            minifyJS: true,
                            minifyCSS: true
                        });
                        resolve(code);
                    } else {
                        // console.log(e)
                        resolve("");
                    }
                });
            });
        });
    }

    cache() {
        let mapPath = Path.resolve(this._config.cachePath, './.ada.cache.map');
        return new File(mapPath).write(JSON.stringify(this._cacheMap, null, 4));
    }
}

module.exports = Maker;